package com.multichannel;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.*;
import java.util.concurrent.CompletableFuture;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * https://www.jianshu.com/p/25b328753017
 * @author yuandf
 */
public class ZipDemoTest {
    private static String ZIP_FILE = "D:\\Users\\yuandf\\Desktop\\test\\test.zip";
    private static String JPG_FILE = "D:\\Users\\yuandf\\Desktop\\test\\app.7z";
    private static String FILE_NAME = "log-";

    public static void main(String[] args) {
        // 共用时：90612
        //zipFileNoBuffer();
        // 共用时：2428
        //zipFileBuffer();
        // 共用时：1415
        //zipFileChannel();
        // 共用时：1338
        //zipFileMap();
        // 共用时：2494
        zipFilePip();
    }

    public static void zipFileNoBuffer() {
        System.out.println("start....");
        File zipFile = new File(ZIP_FILE);
        try (final ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) {
            final long start = System.currentTimeMillis();

            for (int i = 0, len = 10; i < len; i++) {
                System.out.println("第" + i + "次循环压缩");
                try (InputStream is = new FileInputStream(JPG_FILE)) {
                    zipOut.putNextEntry(new ZipEntry(FILE_NAME + i));
                    int temp;
                    while ((temp = is.read()) != -1) {
                        zipOut.write(temp);
                    }
                }
            }
            System.out.println("共用时：" + (System.currentTimeMillis() - start));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("end....");
    }

    public static void zipFileBuffer() {
        System.out.println("start....");
        File zipFile = new File(ZIP_FILE);
        try (
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(zipOut)
        ) {
            final long start = System.currentTimeMillis();

            for (int i = 0, length = 10; i < length; i++) {
                System.out.println("第" + i + "次循环压缩");
                try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(new File(JPG_FILE)))) {
                    zipOut.putNextEntry(new ZipEntry(FILE_NAME + i));
                    int temp;
                    while ((temp = bufferedInputStream.read()) != -1) {
                        bufferedOutputStream.write(temp);
                    }
                }
            }
            System.out.println("共用时：" + (System.currentTimeMillis() - start));

        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("end....");
    }

    public static void zipFileChannel() {
        System.out.println("start....");
        File zipFile = new File(ZIP_FILE);

        try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
             WritableByteChannel writableByteChannel = Channels.newChannel(zipOut);
        ) {
            final long start = System.currentTimeMillis();

            for (int i = 0, length = 10; i < length; i++) {
                System.out.println("第" + i + "次循环压缩");
                final File file = new File(JPG_FILE);
                try (FileChannel fileChannel = new FileInputStream(file).getChannel()) {
                    zipOut.putNextEntry(new ZipEntry(FILE_NAME + i));
                    fileChannel.transferTo(0, file.length(), writableByteChannel);
                }
            }
            System.out.println("共用时：" + (System.currentTimeMillis() - start));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("end....");
    }

    public static void zipFileMap() {
        System.out.println("start....");
        File zipFile = new File(ZIP_FILE);

        try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
             WritableByteChannel writableByteChannel = Channels.newChannel(zipOut);
        ) {
            final long start = System.currentTimeMillis();

            for (int i = 0, length = 10; i < length; i++) {
                System.out.println("第" + i + "次循环压缩");
                zipOut.putNextEntry(new ZipEntry(FILE_NAME + i));
                final File file = new File(JPG_FILE);
                MappedByteBuffer mappedByteBuffer = new RandomAccessFile(JPG_FILE, "r")
                        .getChannel()
                        .map(FileChannel.MapMode.READ_ONLY, 0, file.length());

                writableByteChannel.write(mappedByteBuffer);
            }
            System.out.println("共用时：" + (System.currentTimeMillis() - start));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("end....");
    }

    public static void zipFilePip() {
        System.out.println("start....");
        try (WritableByteChannel out = Channels.newChannel(new FileOutputStream(ZIP_FILE))) {
            final long start = System.currentTimeMillis();
            Pipe pipe = Pipe.open();
            //异步任务
            CompletableFuture.runAsync(() -> runTask(pipe));

            //获取读通道
            ReadableByteChannel readableByteChannel = pipe.source();

            ByteBuffer buffer = ByteBuffer.allocate(((int) new File(JPG_FILE).length()) * 10);
            while (readableByteChannel.read(buffer) >= 0) {
                buffer.flip();
                out.write(buffer);
                buffer.clear();
            }
            System.out.println("共用时：" + (System.currentTimeMillis() - start));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("end....");
    }

    private static void runTask(Pipe pipe) {
        try (ZipOutputStream zos = new ZipOutputStream(Channels.newOutputStream(pipe.sink()));
             WritableByteChannel out = Channels.newChannel(zos)) {
            for (int i = 0, length = 10; i < length; i++) {
                System.out.println("第" + i + "次循环压缩");
                zos.putNextEntry(new ZipEntry(FILE_NAME + i));

                FileChannel jpgChannel = new FileInputStream(new File(JPG_FILE)).getChannel();

                jpgChannel.transferTo(0, new File(JPG_FILE).length(), out);

                jpgChannel.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
